<?php

/**
 * paas接口基类
 * Date: 2018/11/21
 */

namespace Lib\Paas;

use Lib\Base\Common;
use Lib\Base\Config;
use Lib\Base\HttpRequest;
use Lib\Base\L5;
use Lib\Base\Request;
use Lib\Base\Validate;
use Lib\Service\TGLog;

class Base
{
    protected $http;
    private $signInfo;
    private $loginInfo;
    private $getData;

    public function __construct($sData = [])
    {
        $this->loginInfo = [];
        $this->initLogin();
        $this->http = new HttpRequest(['timeout' => 6, 'decode' => true, 'cookie' => true]);
        $this->getData = $sData;
    }

    public function getLoginInfo()
    {
        return $this->loginInfo;
    }

    /**
     * 生成接口调用签名和对应的参数
     * @return
     */
    public function getPaasSign($apiName, $game = '')
    {
        $this->signInfo = array();
        $this->signInfo['game'] = $game === '' ? Request::param('game') : $game;
        $this->signInfo['iActId'] = Request::param('iActId');
        $this->signInfo['sApiName'] = $apiName;
        $this->signInfo['sAppId'] = ULINK_SAPPID;
        $this->signInfo['sVersion'] = ULINK_SVERSION;
        $this->signInfo['timestamp'] = Request::param('timestamp');
        if (!preg_match('/^1(\d{9}|\d{12})$/', $this->signInfo['timestamp'])) {
            $this->signInfo['timestamp'] = time();
        }
        $sToken = Config::getsToken();
        if (!$sToken) {
            recordLog('生成接口签名时获取校验token异常！', __FILE__, __LINE__, LP_ERROR);
            return false;
        }

        $this->signInfo['sSign'] = Common::genToken($this->signInfo, ['sToken' => $sToken]);
        if ($this->signInfo['sSign'] === false) {
            recordLog('生成接口签名异常！', __FILE__, __LINE__, LP_ERROR);
            return false;
        }
        return $this->signInfo;
    }

    /**
     * 获取paas接口请求url
     */
    public function getPaasUrl()
    {
        $host = '';
        if (defined('PASS_TEST') && PASS_TEST == '1') {
            $host = 'https://ulink.game.qq.com/tpaas/';
        } else if (defined('PASS_PRE') && PASS_PRE == '1') {
            $host = 'https://ulink.game.qq.com/ppaas/';
        } else {
            $host = 'https://ulink.game.qq.com/paas/';
        }

        if (ENV == 'test') {
            return $host;
        } else {
            if (defined('PASS_TEST') && PASS_TEST == '1') {
                $l5Info = L5::getHostInfo(64069121, 102301696);
            } elseif (defined('PASS_PRE') && PASS_PRE == '1') {
                $l5Info = L5::getHostInfo(64069121, 108199936);
            } else {
                $game = Request::param('game');
                if (isset(ULINK_PAAS_L5_SID[$game])) {
                    $l5Info = L5::getHostInfo(ULINK_PAAS_L5_SID[$game][0], ULINK_PAAS_L5_SID[$game][1]);
                } else {
                    $l5Info = L5::getHostInfo(ULINK_PAAS_L5_SID['default'][0], ULINK_PAAS_L5_SID['default'][1]);
                }
            }

            if ($l5Info !== false) {
                return $l5Info['url'];
            } else {
                return $host;
            }
        }
    }

    /**
     * 构造paas请求url
     * @param string $apiName paas接口名称
     * @param array $queryData 查询字符串数据，key为字段名，value为值，默认空数组
     * @param bool $needLogin paas接口是否需要校验登录态，默认需要。需要校验登录态时会把登录态相关信息一起传入paas接口
     * @return string|bool 成功：带查询字符串的url，失败：false
     *
     */
    public function getPaasRequestUrl($apiName, $queryData = [], $needLogin = true)
    {
        $paasUrl = $this->getPaasUrl();

        if (is_array($this->getData) && !empty($this->getData)) {
            $queryData = array_merge($queryData, $this->getData);
        }
        $queryData['sUserIP'] = Common::getClientIp();
        $queryString = $this->getPaasQueryParam($apiName, $queryData, $needLogin);
        if ($queryString === false) {
            return false;
        }

        $url = $paasUrl . '?' . $queryString;
        recordLog('paas接口请求url：' . var_export($url, true), __FILE__, __LINE__);
        return $url;
    }

    /**
     *  构造paas请求的查询字符串
     * @param string $apiName paas接口名称
     * @param array $queryData 查询字符串数据，key为字段名，value为值，默认空数组
     * @param bool $needLogin paas接口是否需要校验登录态，默认需要。需要校验登录态时会把登录态相关信息一起传入paas接口
     * @return string 带查询字符串的url
     */
    public function getPaasQueryParam($apiName, $queryData = [], $needLogin = true)
    {
        $param1 = [];
        if ($apiName != '') {
            $param1 = $this->getPaasSign($apiName);
        } else {
            recordLog('apiname不能为空！', __FILE__, __LINE__, LP_ERROR);
            return false;
        }

        $param2 = [];
        if ($needLogin) {
            $param2 = $this->getLoginAuthInfo();
        }

        if (!is_array($queryData)) {
            $queryData = [];
        }

        $queryParam = array_merge($param1, $param2, $queryData);

        if (Request::param('sAmsSerial')) {
            $queryParam['sAmsSerial'] = Request::param('sAmsSerial');
        }

        //带上环境env
        if (defined('ENV')) {
            $queryParam['ulenv'] = ENV;
        }

        return http_build_query($queryParam);
    }

    /**
     * 初始化登录态相关的参数信息
     * @return null
     */
    private function initLogin()
    {
        recordLog(__METHOD__ . '开始执行。', __FILE__, __LINE__);

        $skey = Request::cookieParam('skey');
        $pskey = Request::cookieParam('p_skey');
        $accessToken = Request::param('access_token');

        //登录态优先取sCode
        if (!empty(Request::param('sCode')) && Validate::checkScode(Request::param('sCode'))) {
            $this->loginInfo['type'] = 'scode';
            $this->loginInfo['data']['sCode'] = Request::param('sCode');
            recordLog("scode_Data=" . var_export($this->loginInfo, true), __FILE__, __LINE__);
        } else if (!empty(Request::param('msdkEncodeParam'))) {
            //msdk登录态，直接将登录态参数通过url传递
            $this->loginInfo['type'] = 'msdk';
            $this->loginInfo['data']['sig'] = Request::param('sig');
            $this->loginInfo['data']['msdkTime'] = Request::param('timestamp');
            $this->loginInfo['data']['appid'] = Request::param('appid');
            $this->loginInfo['data']['version'] = Request::param('version');
            $this->loginInfo['data']['algorithm'] = Request::param('algorithm');
            $this->loginInfo['data']['encode'] = Request::param('encode');
            $this->loginInfo['data']['msdkEncodeParam'] = Request::param('msdkEncodeParam');
            recordLog("msdk_Data=" . var_export($this->loginInfo, true), __FILE__, __LINE__);
        } else if (!empty(Request::param('itopencodeparam'))) {
            //msdk-v5登录态，直接将登录态参数通过url传递
            $this->loginInfo['type'] = 'msdk';
            $this->loginInfo['data']['channelid'] = Request::param('channelid');
            $this->loginInfo['data']['gameid'] = Request::param('gameid');
            $this->loginInfo['data']['os'] = Request::param('os');
            $this->loginInfo['data']['source'] = Request::param('source');
            $this->loginInfo['data']['ts'] = Request::param('ts');
            $this->loginInfo['data']['sig'] = Request::param('sig');
            $this->loginInfo['data']['itopencodeparam'] = Request::param('itopencodeparam');
            recordLog("msdk-v5_Data=" . var_export($this->loginInfo, true), __FILE__, __LINE__);
        } else if (
            !empty($accessToken) && $accessToken != $skey && $accessToken != $pskey
            && Validate::checkOpenid(Request::param('authOpenid'), 'wq')
        ) {
            //互联或者微信授权登录,登录态信息加密之后传递
            $this->loginInfo['type'] = 'oauth';
            $this->loginInfo['data']['access_token'] = $accessToken;
            $this->loginInfo['data']['appid'] = Request::param('appid');
            $this->loginInfo['data']['openid'] = Request::param('authOpenid');
            recordLog("access_token_Data=" . var_export($this->loginInfo, true), __FILE__, __LINE__);
        } else if (!empty(Request::cookieParam('p_uin')) && !empty(Request::cookieParam('p_skey'))) {
            //PT登录，登录态信息加密之后传递，另外传递cookie信息
            $this->loginInfo['type'] = 'pt';
            $this->loginInfo['data']["appid"] = Request::param('appid');
            $this->loginInfo['data']['skey'] = Request::cookieParam('p_skey');
            $this->loginInfo['data']['uin'] = Request::cookieParam('p_uin');
            recordLog("pt_Data=" . var_export($this->loginInfo, true), __FILE__, __LINE__);
        } else if (!empty(Request::cookieParam('uin')) && !empty(Request::cookieParam('skey'))) {
            //PT登录，登录态信息加密之后传递，另外传递cookie信息
            $this->loginInfo['type'] = 'pt';
            $this->loginInfo['data']["appid"] = Request::param('appid');
            $this->loginInfo['data']['skey'] = Request::cookieParam('skey');
            $this->loginInfo['data']['uin'] = Request::cookieParam('uin');
            recordLog("pt_Data=" . var_export($this->loginInfo, true), __FILE__, __LINE__);
        } else {
            recordLog("当前请求中没有匹配到合法的登录态信息！", __FILE__, __LINE__);
        }
    }

    /**
     * 获取登陆认证信息,不用传递参数，自动获取相关参数信息
     * @return array 加密之后的登录态信息
     */
    public function getLoginAuthInfo()
    {
        $param = array();
        //互联或者微信开放平台授权登录,PT登录需要加密登录态信息
        if ($this->loginInfo['type'] == 'msdk') {
            $param = $this->loginInfo['data'];
        } else if ($this->loginInfo['type'] == 'oauth' || $this->loginInfo['type'] == 'pt') {
            $param['sCode'] = Common::encryptData($this->loginInfo['data']);
        } else if ($this->loginInfo['type'] == 'scode') {
            $param['sCode'] = $this->loginInfo['data']['sCode'];
        }
        return $param;
    }

    /**
     * 解析资格查询的paas接口返回数据
     */
    protected function getQualRetData($qualInfo, $res)
    {
        $rtnData['sPaasSerial'] = $res['sSerial'];

        foreach ($qualInfo as $key => $value) {
            if ($res['ret'] != '0' || $res['data'][$key]['iRet'] != '0') {
                $iRet = $res['ret'] != '0' ? $res['ret'] : $res['data'][$key]['iRet'];
                return $this->getRetData($iRet, '系统繁忙，请稍后再试！', ['sPaasSerial' => $res['sSerial']]);
            } else {
                $rtnData['data'][$key] = $res['data'][$key]['data'];
                $rtnData['data'][$key]['type'] = $res['data'][$key]['type'];
            }
        }
        return $this->getRetData(0, 'success', $rtnData);
    }

    protected function getRetData($ret, $msg, $data = [])
    {
        return array_merge($data, ['iRet' => $ret, 'sMsg' => $msg]);
    }

    /**
     * paas接口异常上报tglog
     * @param string $errorMsg 异常消息
     * @param string $apiName 异常接口
     */
    protected function tglogReport($errorMsg, $apiName)
    {
        if (RUN_ENV == 'ulink' && ENV != 'test') {
            $data = [
                ULINK_SAPPID, //sAppid
                Request::param('game'), //sAppKey
                Request::param('iActId'), //活动ID
                Request::param('openid'), //openid
                PAAS_CONNECT_ERROR, //错误码
                $errorMsg, //错误内容
                Request::serverParam('SERVER_ADDR'), //服务器ID
                Request::getParam('sAmsSerial'), //流水号
                date('Y-m-d H:i:s'), //时间
                '',
                '',
                '',
                $apiName, //sApiName
            ];
            $tglog = new TGLog(TGLOG_SERVER_INFO);
            $tglog->setTbName('UlinkVitalError');
            $tglog->sendLog($data);
        }
    }
}
